﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace startup.Common.Json
{
    public class JsonObject :JsonValue, IDictionary<string, JsonValue>
    {
        private readonly Dictionary<string, JsonValue> _values = new Dictionary<string, JsonValue>();

        #region 公开属性

        internal override object Value
        {
            get { return _values; }
        }

        public override sealed JsonType JsonType
        {
            get { return JsonType.Object; }
        }

        public ICollection<string> Keys
        {
            get { return _values.Keys; }
        }

        public ICollection<JsonValue> Values
        {
            get { return _values.Values; }
        }

        public override sealed JsonValue this[string key]
        {
            get { return _values[key]; }
            set { _values[key] = value; }
        }

        public override sealed int Count
        {
            get { return _values.Count; }
        }

        bool ICollection<KeyValuePair<string, JsonValue>>.IsReadOnly
        {
            get { return false; }
        }

        #endregion

        #region 构造函数

        /// <summary>
        ///     通过字典构造Json对象
        /// </summary>
        /// <param name="dictValue">字典对象</param>
        internal JsonObject(IDictionary dictValue)
        {
            CheckNull(dictValue, "dictValue");
            IDictionaryEnumerator enumerator = dictValue.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    var dictionaryEntry = (DictionaryEntry)enumerator.Current;
                    _values.Add((string)dictionaryEntry.Key, Convert(dictionaryEntry.Value));
                }
            }
            finally
            {
                var disposable = enumerator as IDisposable;
                if (disposable != null)
                {
                    disposable.Dispose();
                }
            }
        }

        /// <summary>
        ///     通过集合、数组构造Json对象
        /// </summary>
        /// <param name="items">集合对象</param>
        public JsonObject(IEnumerable<KeyValuePair<string, JsonValue>> items)
        {
            CheckNull(items, "items");
            AddRange(items);
        }

        /// <summary>
        ///     通过可变参数构造Json对象
        /// </summary>
        /// <param name="items"></param>
        public JsonObject(params KeyValuePair<string, JsonValue>[] items)
        {
            if (items != null)
            {
                AddRange(items);
            }
        }

        #endregion

        #region 接口方法

        /// <summary>
        ///     将指定的键值对元素添加到 JsonObject 对象。
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        public void Add(string key, JsonValue value)
        {
            CheckNull(key, "key");
            _values.Add(key, value);
        }

        /// <summary>
        ///     将指定的键对值元素添加到 JsonObject 对象。
        /// </summary>
        /// <param name="item">键值对对象</param>
        public void Add(KeyValuePair<string, JsonValue> item)
        {
            CheckNull(item, "item");
            _values.Add(item.Key, item.Value);
        }

        /// <summary>
        ///     确定 JsonObject 是否包含指定的键。
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public override bool ContainsKey(string key)
        {
            CheckNull(key, "key");
            return _values.ContainsKey(key);
        }

        /// <summary>
        ///     从 JsonObject 中移除所指定的键的值。
        /// </summary>
        /// <param name="key">要移除的元素的键</param>
        /// <returns>如果成功找到并移除该元素，则为 true；否则为 false。如果在 JsonObject 中没有找到 key，此方法则返回 false</returns>
        public bool Remove(string key)
        {
            CheckNull(key, "key");
            return _values.Remove(key);
        }

        /// <summary>
        ///     获取与指定的键相关联的值。
        /// </summary>
        /// <param name="key">要获取的值的键</param>
        /// <param name="value">当此方法返回值时，如果找到该键，便会返回与指定的键相关联的值；否则，则会返回 value 参数的类型默认值。该参数未经初始化即被传递。</param>
        /// <returns>如果 JsonObject 包含具有指定键的元素，则为 true；否则为 false。</returns>
        public bool TryGetValue(string key, out JsonValue value)
        {
            CheckNull(key, "key");
            return _values.TryGetValue(key, out value);
        }

        /// <summary>
        ///     从 JsonObject 中移除所有的键和值。
        /// </summary>
        public void Clear()
        {
            _values.Clear();
        }

        public void CopyTo(KeyValuePair<string, JsonValue>[] array, int arrayIndex)
        {
            CheckNull(array, "array");
        }

        public IEnumerator<KeyValuePair<string, JsonValue>> GetEnumerator()
        {
            return _values.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return _values.GetEnumerator();
        }

        /// <summary>
        ///     确定 JsonObject 是否包含指定的对象。
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        bool ICollection<KeyValuePair<string, JsonValue>>.Contains(KeyValuePair<string, JsonValue> item)
        {
            CheckNull(item, "item");
            return _values.ContainsKey(item.Key);
        }

        /// <summary>
        ///     从 JsonObject 中移除所指定的键的值。
        /// </summary>
        /// <param name="item">要移除的元素的键</param>
        /// <returns>如果成功找到并移除该元素，则为 true；否则为 false。如果在 JsonObject 中没有找到 key，此方法则返回 false</returns>
        bool ICollection<KeyValuePair<string, JsonValue>>.Remove(KeyValuePair<string, JsonValue> item)
        {
            CheckNull(item, "item");
            return _values.Remove(item.Key);
        }

        public bool AddOrUpdate(string key, JsonValue value)
        {
            CheckNull(key, "key");
            if (_values.ContainsKey(key))
            {
                _values[key] = value;
                return false;
            }
            _values.Add(key, value);
            return true;
        }

        /// <summary>
        ///     将指定集合的元素添加到 JsonObject 对象。
        /// </summary>
        /// <param name="items"></param>
        public void AddRange(IEnumerable<KeyValuePair<string, JsonValue>> items)
        {
            CheckNull(items, "items");
            using (IEnumerator<KeyValuePair<string, JsonValue>> enumerator = items.GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    KeyValuePair<string, JsonValue> current = enumerator.Current;
                    _values.Add(current.Key, current.Value);
                }
            }
        }

        /// <summary>
        ///     将指定集合的元素添加到 JsonObject 对象。
        /// </summary>
        /// <param name="items"></param>
        public void AddRange(params KeyValuePair<string, JsonValue>[] items)
        {
            CheckNull(items, "items");
            foreach (var keyValuePair in items)
            {
                _values.Add(keyValuePair.Key, keyValuePair.Value);
            }
        }

        #endregion

        /// <summary>
        ///     在StringBuilder中构建该对象的Json格式字符串输出
        /// </summary>
        /// <param name="builder">操作的StringBuilder对象</param>
        internal override void Builder(StringBuilder builder)
        {
            CheckNull(builder, "builder");
            bool flag = false;
            builder.Append('{');
            using (Dictionary<string, JsonValue>.Enumerator enumerator = _values.GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    KeyValuePair<string, JsonValue> current = enumerator.Current;
                    if (flag)
                    {
                        builder.Append(',');
                    }
                    else
                    {
                        flag = true;
                    }

                    if (current.Value == null)
                    {
                        builder.AppendFormat("\"{0}\":null", current.Key);
                    }
                    else
                    {
                        builder.AppendFormat("\"{0}\":", current.Key);
                        current.Value.Builder(builder);
                    }
                }
            }
            builder.Append('}');
        }

        /// <summary>
        ///     将JSON的字符串表示形式转换为Json对象。
        /// </summary>
        /// <param name="s">包含要转换的Json字符串</param>
        /// <returns>一个Json对象</returns>
        public new static JsonObject Parse(string s)
        {
            return (JsonObject)JsonValue.Parse(s);
        }

        /// <summary>
        ///     将JSON的字符串表示形式转换为Json对象。一个指示转换是否成功的返回值。
        /// </summary>
        /// <param name="s">包含要转换的Json字符串</param>
        /// <param name="value">当此方法返回时，如果转换成功，则包含一个Json对象；如果转换失败，则包含 null。</param>
        /// <returns>如果 s 转换成功，则为 true；否则为 false。</returns>
        public static bool TryParse(string s, out JsonObject value)
        {
            if (String.IsNullOrWhiteSpace(s))
            {
                value = null;
                return false;
            }
            JsonValue result;
            //解析JSON字符串
            var parser = new JsonReader(s);
            parser.TryParser(out result);
            value = result as JsonObject;
            return value != null;
        }
    }
}
